package cn.edu.nju.ws.sview.views.data;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;

import cn.edu.nju.ws.sview.cache.URIDatamemberCache;
import cn.edu.nju.ws.sview.cache.URIIDCache;
import cn.edu.nju.ws.sview.cache.URILabelCache;
import cn.edu.nju.ws.sview.database.DBConnectionFactory;
import cn.edu.nju.ws.sview.reasoning.schema.InnerClass;
import cn.edu.nju.ws.sview.reasoning.schema.MyClass;
import cn.edu.nju.ws.sview.util.URIUtil;
import cn.edu.nju.ws.sview.views.DataMember;
import cn.edu.nju.ws.sview.views.Group;
import cn.edu.nju.ws.sview.views.URIDataMember;
import cn.edu.nju.ws.sview.views.User;
import cn.edu.nju.ws.sview.views.View;

/**
 * 管理view的编辑，制作以及翻译
 * @author ssgong
 *
 */
public class ViewEditing {
	public static String CATEGORY_FORWARD = "forward";
	public static String CATEGORY_BACKWARD = "backward";
	public static String CATEGORY_MYGROUP = "mygroup";
	public static String CATEGORY_OHTERGROUPS= "othergroups";
	public static String CATEGORY_ALLGROUPS= "usergroups";
	public static String CATEGORY_FAVORITE = "favorite";
	public static String CATEGORY_AVAILABLE = "available";
	public static String CATEGORY_TRASHED = "trashed";
	public static String CATEGORY_FORWARD_ZH = "前向属性";
	public static String CATEGORY_BACKWARD_ZH = "后向属性";
	public static String CATEGORY_MYGROUP_ZH = "我的组";
	public static String CATEGORY_OHTERGROUPS_ZH= "其它组";
	public static String CATEGORY_ALLGROUPS_ZH= "用户组";
	public static String CATEGORY_FAVORITE_ZH = "喜爱的视图";
	public static String CATEGORY_AVAILABLE_ZH = "可用的视图";
	public static String CATEGORY_TRASHED_ZH = "回收站";
	
	public static ArrayList<ViewItem> kw2View(String user,String keyword, String lang,boolean isInner,int classID){
		keyword = keyword.trim();
		ArrayList<ViewItem> result = new ArrayList<ViewItem>();

		if (user != null) {
			ArrayList<View> favorViews = View.getFavorViews(isInner, classID,
					lang, user, 0, -1);
			for (View view : favorViews) {
				String name = view.getName();
				if (name.toLowerCase().startsWith(keyword.toLowerCase())) {
					String ctgry = CATEGORY_FAVORITE;
					if(lang.equals("zh")){
						ctgry = CATEGORY_FAVORITE_ZH;
					}
					ViewItem item = new ViewItem(view.getID(), name,
							ctgry);
					result.add(item);
				}
			}
		}
		ArrayList<View> allViews = View.getPopViews(isInner, classID, lang,
				user, 0, -1);
		for (View view : allViews) {
			String name = view.getName();
			if (name.toLowerCase().startsWith(keyword.toLowerCase())) {
				String ctgry = CATEGORY_AVAILABLE;
				if(lang.equals("zh")){
					ctgry = CATEGORY_AVAILABLE_ZH;
				}
				ViewItem item = new ViewItem(view.getID(), name,
						ctgry);
				result.add(item);
			}
		}
		if (user != null) {
			ArrayList<View> trashviews = View.getTrashedViews(isInner, classID,
					lang, user, 0, -1);
			for (View view : trashviews) {
				String name = view.getName();
				if (name.toLowerCase().startsWith(keyword.toLowerCase())) {
					String ctgry = CATEGORY_TRASHED;
					if(lang.equals("zh")){
						ctgry = CATEGORY_TRASHED_ZH;
					}
					ViewItem item = new ViewItem(view.getID(), name,
							ctgry);
					result.add(item);
				}
			}
		}
		return result;
	}
	
	
	
	public static ArrayList<DataMemberItem> kw2Datamember(int groupID,String keyword, String lang,int etype,int eid,boolean isInner,int classID){
		keyword = keyword.trim();
		ArrayList<DataMemberItem> result = new ArrayList<DataMemberItem>();
		HashSet<DataMemberItem> items = new HashSet<DataMemberItem>();
		
		HashSet<MyClass> classIDs = new HashSet<MyClass>();
		classIDs = InnerClass.getSuperClass(isInner,classID) ;
		
    	try {
    		Connection conn = DBConnectionFactory.getConnection();
    		 String like = keyword+"%" ;
 			try {
				/* get forward uri datamember */
 				ArrayList<DataMemberItem> fdatamembers = new ArrayList<DataMemberItem>();
				HashSet<Integer> ids = URIDatamemberCache.getInstance()
						.getForwardDataMembers(etype, eid);
				for (Integer mid : ids) {
					String label = URILabelCache.getInstance().getLabel(mid,
							lang);
					if(label.equals(""))
						label = URIUtil.getLocalname(URIIDCache.getInstance().getURI(mid)) ;
					if (label.toLowerCase().startsWith(keyword.toLowerCase())) {
						int value_type = URIDataMember.getValueTypeByDMId(mid,false);
						String ctgry = CATEGORY_FORWARD;
						if(lang.equals("zh")){
							ctgry = CATEGORY_FORWARD_ZH;
						}
						DataMemberItem quadItem = new DataMemberItem(ctgry,
								DataMember.URI_DATAMEMBER, mid, label, false,value_type,2,false,true);
						if(!items.contains(quadItem)){
							fdatamembers.add(quadItem);
							items.add(quadItem);
						}
					}
				}
				Collections.sort(fdatamembers);
				result.addAll(fdatamembers);

				/* get backward uri datamember */
				ArrayList<DataMemberItem> bdatamembers = new ArrayList<DataMemberItem>();
				ids = URIDatamemberCache.getInstance().getBackwardDataMembers(
						etype, eid);
				for (Integer mid : ids) {
					String label = URILabelCache.getInstance().getLabel(mid,
							lang);
					if(label.equals(""))
						label = URIUtil.getLocalname(URIIDCache.getInstance().getURI(mid)) ;
					if (label.toLowerCase().startsWith(keyword.toLowerCase())) {
						int value_type = URIDataMember.getValueTypeByDMId(mid,true);
						String ctgry = CATEGORY_BACKWARD;
						if(lang.equals("zh")){
							ctgry = CATEGORY_BACKWARD_ZH;
						}
						DataMemberItem quadItem = new DataMemberItem(ctgry,
								DataMember.URI_DATAMEMBER, mid, label, true,value_type,2,false,true);
						if(!items.contains(quadItem)){
							bdatamembers.add(quadItem);
							items.add(quadItem);
						}
					}
				}
				Collections.sort(bdatamembers);
				result.addAll(bdatamembers);
			} catch (Throwable e) {
				e.printStackTrace();
			}    	
			
			ArrayList<DataMemberItem> mygroup = new ArrayList<DataMemberItem>();
			ArrayList<DataMemberItem> othergroups = new ArrayList<DataMemberItem>();
    		/*get custom datamember*/
    	    PreparedStatement ps = conn.
	            prepareStatement("select id,group_id,name,value_type,arity,functional from data_member where class_id=? and isInner=? and name COLLATE utf8_general_ci like ? and isCopy=0 ") ;
    	    for(MyClass myclass:classIDs){
    	    	ps.setInt(1, myclass.getClassID()) ;
    	    	ps.setBoolean(2, myclass.isInner()) ;
    	    	ps.setString(3, like) ;
    	    	ResultSet rs = ps.executeQuery();
    	    	while(rs.next()){
    	    		int id = rs.getInt("id") ;
    	    		int gid = rs.getInt("group_id");
    	    		boolean hasAuthor =groupID==gid;
    	    		
    	    		String name =  rs.getString("name") ;
    	    		int value_type =rs.getInt("value_type") ;
    	    		int arity = rs.getInt("arity") ;
    	    		boolean functional  = rs.getBoolean("functional") ;
    	    		String category = CATEGORY_MYGROUP;
    	    		if(!hasAuthor){
    	    			category = CATEGORY_OHTERGROUPS;
    	    		}
    	    		//表示未登录用户
    	    		if(groupID<=0){
    	    			category = CATEGORY_ALLGROUPS;
    	    		}
    	    		String ctgry = category;
					if(lang.equals("zh")){
						if(groupID<=0){
							ctgry = CATEGORY_ALLGROUPS_ZH;
						}else if(category.equals(CATEGORY_MYGROUP))
							ctgry = CATEGORY_MYGROUP_ZH;
						else
							ctgry = CATEGORY_OHTERGROUPS_ZH;
					}
    	    		DataMemberItem item = new DataMemberItem(ctgry,DataMember.CUSTOM_DATAMEMBER,id,name,false,value_type,arity,functional,hasAuthor);
    	    		if(!items.contains(item)){
						items.add(item);
						if(category.equals(CATEGORY_MYGROUP))
							mygroup.add(item);
						else
							othergroups.add(item);
					}
    	    	}
    	    	rs.close();
    	    }
    	    Collections.sort(mygroup);
    	    result.addAll(mygroup);
    	    Collections.sort(othergroups);
    	    result.addAll(othergroups);
    	    ps.close();
    	    conn.close();
    	} catch (SQLException e) {
    		e.printStackTrace();
		}
    	return result;
	}
	
	/**
	 * 计算一个实体（可能是自定义）拥有的原始前向属性
	 * @param lang
	 * @param etype
	 * @param eid
	 * @param moreInfo.是否计算类型等信息
	 * @return
	 */
	public static ArrayList<DataMemberItem> getForwardDM(String lang,int etype,int eid,boolean moreInfo){
		ArrayList<DataMemberItem> result = new ArrayList<DataMemberItem>();
		HashSet<DataMemberItem> items = new HashSet<DataMemberItem>();

		try {
			Connection conn = DBConnectionFactory.getConnection();

			try {
				/* get forward uri datamember */
				HashSet<Integer> ids = URIDatamemberCache.getInstance().getForwardDataMembers(
						etype, eid);
				for (Integer mid : ids) {
					DataMemberItem quadItem;
					if (moreInfo) {
						String label = URILabelCache.getInstance().getLabel(
								mid, lang);
						if (label.equals(""))
							label = URIUtil.getLocalname(URIIDCache
									.getInstance().getURI(mid));
						int value_type = URIDataMember.getValueTypeByDMId(mid,
								false);
						quadItem = new DataMemberItem(CATEGORY_FORWARD,DataMember.URI_DATAMEMBER, mid,
								label, false, value_type, 2, false, true);
					} else {
						quadItem = new DataMemberItem(DataMember.URI_DATAMEMBER, mid,
								false);
					}
					items.add(quadItem);
				}

			} catch (Throwable e) {
				e.printStackTrace();
			}
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		result.addAll(items);
		if(moreInfo)
			Collections.sort(result);
		return result;
	}
	
	public static ArrayList<DataMemberItem> getBackwardDM(String lang,int etype,int eid,boolean moreInfo){
		ArrayList<DataMemberItem> result = new ArrayList<DataMemberItem>();
		HashSet<DataMemberItem> items = new HashSet<DataMemberItem>();

		try {
			Connection conn = DBConnectionFactory.getConnection();

			try {
				HashSet<Integer> ids = URIDatamemberCache.getInstance()
						.getBackwardDataMembers(etype, eid);
				for (Integer mid : ids) {
					DataMemberItem quadItem;
					if(moreInfo){
					String label = URILabelCache.getInstance().getLabel(mid,
							lang);
					if (label.equals(""))
						label = URIUtil.getLocalname(URIIDCache.getInstance()
								.getURI(mid));
					int value_type = URIDataMember
							.getValueTypeByDMId(mid, true);
					quadItem = new DataMemberItem(CATEGORY_BACKWARD,DataMember.URI_DATAMEMBER, mid,
							label, true, value_type, 2, false, true);
					}else{
						quadItem = new DataMemberItem(DataMember.URI_DATAMEMBER, mid,true);
					}
					items.add(quadItem);
				}

			} catch (Throwable e) {
				e.printStackTrace();
			}
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		result.addAll(items);
		if(moreInfo)
			Collections.sort(result);
		return result;
	}
	
	public static ArrayList<DataMemberItem> getCustomDM(String lang,boolean isInner,int classID,boolean moreInfo){
		ArrayList<DataMemberItem> result = new ArrayList<DataMemberItem>();
		HashSet<DataMemberItem> items = new HashSet<DataMemberItem>();

		HashSet<MyClass> classIDs = new HashSet<MyClass>();
		classIDs = InnerClass.getSuperClass(isInner, classID);

		try {
			Connection conn = DBConnectionFactory.getConnection();
			/* get custom datamember */
			PreparedStatement ps = conn
					.prepareStatement("select id,name,value_type,arity,functional from data_member where class_id=? and isInner=?  and isCopy = 0");
			for (MyClass myclass : classIDs) {
				ps.setInt(1, myclass.getClassID());
				ps.setBoolean(2, myclass.isInner());
				ResultSet rs = ps.executeQuery();
				while (rs.next()) {
					int id = rs.getInt("id");
					DataMemberItem item;
					if (moreInfo) {
						String name = rs.getString("name");
						int value_type = rs.getInt("value_type");
						int arity = rs.getInt("arity");
						boolean functional = rs.getBoolean("functional");
						item = new DataMemberItem(CATEGORY_ALLGROUPS,DataMember.CUSTOM_DATAMEMBER, id, name,
								false, value_type, arity, functional, true);
					} else {
						item = new DataMemberItem(DataMember.CUSTOM_DATAMEMBER, id, false);
					}
					items.add(item);
				}
				rs.close();
			}
			ps.close();
			conn.close();
		} catch (Throwable e) {
			e.printStackTrace();
		}
        result.addAll(items);
		return result;
	}
	
	public static ArrayList<DataMemberItem> getMyGroupDM(int groupID,boolean isInner,int classID,boolean moreInfo){
		ArrayList<DataMemberItem> result = new ArrayList<DataMemberItem>();
		HashSet<DataMemberItem> items = new HashSet<DataMemberItem>();

		HashSet<MyClass> classIDs = new HashSet<MyClass>();
		classIDs = InnerClass.getSuperClass(isInner, classID);

		try {
			Connection conn = DBConnectionFactory.getConnection();
			/* get custom datamember */
			PreparedStatement ps = conn
					.prepareStatement("select id,name,value_type,arity,functional from data_member where class_id=? and isInner=? and group_id=? and isCopy = 0");
			for (MyClass myclass : classIDs) {
				ps.setInt(1, myclass.getClassID());
				ps.setBoolean(2, myclass.isInner());
				ps.setInt(3, groupID);
				ResultSet rs = ps.executeQuery();
				while (rs.next()) {
					int id = rs.getInt("id");

					DataMemberItem item;
					if (moreInfo) {
						String name = rs.getString("name");
						int value_type = rs.getInt("value_type");
						int arity = rs.getInt("arity");
						boolean functional = rs.getBoolean("functional");
						item = new DataMemberItem(CATEGORY_MYGROUP,DataMember.CUSTOM_DATAMEMBER, id, name,
								false, value_type, arity, functional, true);
					} else {
						item = new DataMemberItem(DataMember.CUSTOM_DATAMEMBER, id, false);
					}
					items.add(item);
				}
				rs.close();
			}
			ps.close();
			conn.close();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		result.addAll(items);
		if(moreInfo)
			Collections.sort(result);
		return result;
	}	
	
	public static int getMyGroupDMTotalNum(int groupID, boolean isInner,int classID){
		int count = 0;

		HashSet<MyClass> classIDs = new HashSet<MyClass>();
		classIDs = InnerClass.getSuperClass(isInner, classID);
      
		try {
			Connection conn = DBConnectionFactory.getConnection();
			/* get custom datamember */
			PreparedStatement ps = conn
					.prepareStatement("select count(*) as num from data_member where class_id=? and isInner=? and group_id=? and isCopy = 0");
			for (MyClass myclass : classIDs) {
				ps.setInt(1, myclass.getClassID());
				ps.setBoolean(2, myclass.isInner());
				ps.setInt(3, groupID);
				ResultSet rs = ps.executeQuery();
				if(rs.next()){
					int num = rs.getInt("num") ;
					count+=num;
				}
				rs.close();
			}
			ps.close();
			conn.close();
		} catch (Throwable e) {
			e.printStackTrace();
		}

		return count;
	}	
	
	public static ArrayList<DataMemberItem>  getOtherGroupDM(int groupID,boolean isInner,int classID,boolean moreInfo){
		ArrayList<DataMemberItem> result = new ArrayList<DataMemberItem>();
		HashSet<DataMemberItem> items = new HashSet<DataMemberItem>();

		HashSet<MyClass> classIDs = new HashSet<MyClass>();
		classIDs = InnerClass.getSuperClass(isInner, classID);

		try {
			Connection conn = DBConnectionFactory.getConnection();
			/* get custom datamember */
			PreparedStatement ps = conn
					.prepareStatement("select id,name,value_type,arity,functional from data_member where class_id=? and isInner=? and group_id!=? and isCopy=0 ");
			for (MyClass myclass : classIDs) {
				ps.setInt(1, myclass.getClassID());
				ps.setBoolean(2, myclass.isInner());
				ps.setInt(3, groupID);
				ResultSet rs = ps.executeQuery();
				while (rs.next()) {
					int id = rs.getInt("id");

					DataMemberItem item;
					if(moreInfo){
					String name = rs.getString("name");
					int value_type = rs.getInt("value_type");
					int arity = rs.getInt("arity");
					boolean functional = rs.getBoolean("functional");
					item = new DataMemberItem(CATEGORY_OHTERGROUPS,DataMember.CUSTOM_DATAMEMBER, id,
							name, false, value_type, arity, functional, false);
					}else{
						item = new DataMemberItem(DataMember.CUSTOM_DATAMEMBER, id,false);
					}
					items.add(item);
				}
				rs.close();
			}
			ps.close();
			conn.close();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		result.addAll(items);
		if(moreInfo)
			Collections.sort(result);
		return result;
	}	
	
	/**
	 * 判断以viewID1 和viewID2标识的两个view是否是属于同一个ov id
	 * @param viewID1
	 * @param viewID2
	 * @return
	 */
	public static boolean isSameOV(int viewID1 ,int viewID2){
		boolean flag = false;
		try {
			Connection con = DBConnectionFactory.getConnection();
			Statement stmt = con.createStatement();
					
			ResultSet rs = stmt.executeQuery(String.format(
				"SELECT null FROM view x,view y where x.ov_id = y.ov_id and x.id =%d and y.id =%d",viewID1,viewID2));
			if(rs.next()){
				flag =true;
			}
			rs.close();
			stmt.close();
			
			con.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return flag;
	}
	
	public static class  ViewItem{
			private int viewID;
			private String name;
			private String category;
			
			public ViewItem(int viewID,String name,String category){
				this.viewID = viewID;
				this.name = name;
				this.category = category;
			}
			
			public String getCategory(){
				return this.category;
			}
			
			public String getName(){
				return this.name;
			}
			
			public int getViewID(){
				return this.viewID;
			}

			@Override
			public int hashCode() {
				final int prime = 31;
				int result = 1;
				result = prime * result + viewID;
				return result;
			}


			@Override
			public boolean equals(Object obj) {
				if (this == obj)
					return true;
				if (obj == null)
					return false;
				if (getClass() != obj.getClass())
					return false;
				ViewItem other = (ViewItem) obj;
				if (viewID != other.viewID)
					return false;
				return true;
			}
	}
	
	public static class DataMemberItem implements Comparable<DataMemberItem>{
		private int dmtype;
		private int dmid;
		private String name;
		private boolean inverse;
		private int valueType;
		private int arity;
		private boolean functional;
		private boolean hasAuthor;
		private String category;
		
		/**
		 * constructor
		 * @param dmtype
		 * @param dmid
		 * @param name
		 * @param inverse
		 * @param valueType
		 * @param arity
		 * @param functional
		 */
		public DataMemberItem(String category,int dmtype,int dmid,String name,boolean inverse,int valueType,int arity,boolean functional,boolean hasAuthor){
			this.category = category;
			this.dmid = dmid;
			this.dmtype = dmtype;
			this.name = name;
			this.inverse = inverse;
			this.valueType = valueType;
			this.arity = arity;
			this.functional = functional;
			this.hasAuthor = hasAuthor;
		}
		
		public DataMemberItem(int dmtype,int dmid, boolean inverse){
			this.dmid = dmid;
			this.dmtype = dmtype;
			this.inverse = inverse;
		}
		
		public int getDMType(){
			return this.dmtype;
		}
		
		public String getCategory(){
			return this.category;
		}
		
		public int getDMID(){
			return this.dmid;
		}
		
		public int getArity(){
			return this.arity;
		}
		
		
		public boolean getInverse(){
			return this.inverse;
		}
		
		public String getName(){
			return this.name;
		}
		
		public int getValueType(){
			return this.valueType;
		}
		
		public boolean getFunctional(){
			return this.functional;
		}
		
		public boolean hasAuthor(){
			return this.hasAuthor;
		}

		@Override
		public int compareTo(DataMemberItem arg0) {
			// TODO Auto-generated method stub
			return this.name.toLowerCase().compareTo(arg0.getName().toLowerCase());
		}
		
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + dmid;
			result = prime * result + dmtype;
			result = prime * result + (inverse ? 1231 : 1237);
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			DataMemberItem other = (DataMemberItem) obj;
			if (dmid != other.dmid)
				return false;
			if (dmtype != other.dmtype)
				return false;
			if (inverse != other.inverse)
				return false;
			return true;
		}
	}
}
